
`include "common_header.verilog"

//  *************************************************************************
//   File : lane_dskew_stm.v
//  *************************************************************************
//   This program is controlled by a written license agreement.
//   Unauthorized Reproduction or Use is Expressly Prohibited. 
// 
//  Copyright (c) 2005 Morethanip GmbH
//  info@morethanip.com
//  *************************************************************************
//  Version: $Id: lane_dskew_stm.v,v 1.4 2017/06/07 14:37:54 dk Exp $ 
//  Author : Muhammad Anisur Rahman
//  *************************************************************************
//  Description:
// 
//  PCS deskew state machine 
// 
//  *************************************************************************

module lane_dskew_stm (

   reset,
   clk,
  `ifdef USE_CLK_ENA
   clk_ena,
  `endif   
   rx_sync,
   sudi_col_a,
   deskew_error,
   enable_deskew,
   align_done);
   
input   reset;          //  Asynchronous Reset - Active High
input   clk;            //  156.25MHz Clock
`ifdef USE_CLK_ENA
input   clk_ena;
`endif
input   [3:0] rx_sync;  //  SERDES Lanes Sync Status
input   sudi_col_a;     //  SYNC UNIT DATA indicate column |A|
input   deskew_error;   //  Lane Deskew Error
output  enable_deskew;  //  Enable Lane Deskew 
output  align_done;     //  Alignment completed

reg     enable_deskew; 
reg     align_done; 

parameter STATE_TYP_LOSS_ALIGN = 3'h0;
parameter STATE_TYP_ALIGN_DET1 = 3'h1;
parameter STATE_TYP_ALIGN_DET2 = 3'h2;
parameter STATE_TYP_ALIGN_DET3 = 3'h3;
parameter STATE_TYP_ALIGN_ACQ1 = 3'h4;
parameter STATE_TYP_ALIGN_ACQ2 = 3'h5;
parameter STATE_TYP_ALIGN_ACQ3 = 3'h6;
parameter STATE_TYP_ALIGN_ACQ4 = 3'h7;

reg     [2:0] next_state; 
reg     [2:0] state; 
wire    rx_sync_all; 
reg     enable_deskew_reg; 

//  Clock Domain Synchronization
//  ----------------------------   

wire    [3:0] rx_sync_reg2; 

mtip_xsync #(4) U_SYRDRST (
        .data_in(rx_sync),
        .reset  (reset),
        .clk    (clk),
        .data_s (rx_sync_reg2));

assign rx_sync_all = rx_sync_reg2 == 4'b 1111 ? 1'b 1 : 1'b 0; // ync status = OK, only when it is true for all lanes

always @(posedge reset or posedge clk)
   begin : process_2
   if (reset == 1'b 1)
      begin
      state <= STATE_TYP_LOSS_ALIGN;   
      end
   else
      begin
      
         `ifdef USE_CLK_ENA
            if(clk_ena == 1'b 1)
            begin
         `endif       
      
              if (rx_sync_all == 1'b 0)
                 begin
                 state <= STATE_TYP_LOSS_ALIGN;   
                 end
              else
                 begin
                 state <= next_state;   
                 end
      
         `ifdef USE_CLK_ENA
            end
         `endif      
      
      end
   end

always @(state or sudi_col_a or rx_sync_all or deskew_error)
   begin : process_3
   case (state)
   STATE_TYP_LOSS_ALIGN:
      begin
      if (rx_sync_all == 1'b 0)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else if (sudi_col_a == 1'b 1 )
         begin

   //  ---------------------------------------- //
   //  exit condition when signal detected      //
   //  and code group containes comma character //
   //  ---------------------------------------- //
   
         next_state = STATE_TYP_ALIGN_DET1;   
         end
      else
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   // stay in the same state
         end
      end
   STATE_TYP_ALIGN_DET1:
      begin
      if (rx_sync_all == 1'b 0 | deskew_error == 1'b 1)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_DET2;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_DET1;   
            end
         end
      end
   STATE_TYP_ALIGN_DET2:
      begin
      if (rx_sync_all == 1'b 0 | deskew_error == 1'b 1)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_DET3;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_DET2;   
            end
         end
      end
   STATE_TYP_ALIGN_DET3:
      begin
      if (rx_sync_all == 1'b 0 | deskew_error == 1'b 1)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_ACQ1;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_DET3;   
            end
         end
      end
   STATE_TYP_ALIGN_ACQ1:
      begin
      if (rx_sync_all == 1'b 0)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else if (deskew_error == 1'b 1 )
         begin
         next_state = STATE_TYP_ALIGN_ACQ2;   
         end
      else
         begin
         next_state = STATE_TYP_ALIGN_ACQ1;   
         end
      end
   STATE_TYP_ALIGN_ACQ2:
      begin
      if (rx_sync_all == 1'b 0)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else if (deskew_error == 1'b 1 )
         begin
         next_state = STATE_TYP_ALIGN_ACQ3;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_ACQ1;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_ACQ2;   
            end
         end
      end
   STATE_TYP_ALIGN_ACQ3:
      begin
      if (rx_sync_all == 1'b 0)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else if (deskew_error == 1'b 1 )
         begin
         next_state = STATE_TYP_ALIGN_ACQ4;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_ACQ2;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_ACQ3;   
            end
         end
      end
   STATE_TYP_ALIGN_ACQ4:
      begin
      if (rx_sync_all == 1'b 0 | deskew_error == 1'b 1)
         begin
         next_state = STATE_TYP_LOSS_ALIGN;   
         end
      else
         begin
         if (sudi_col_a == 1'b 1)
            begin
            next_state = STATE_TYP_ALIGN_ACQ3;   
            end
         else
            begin
            next_state = STATE_TYP_ALIGN_ACQ4;   
            end
         end
      end
   endcase
   end

//  Alignment Done
//  --------------	

always @(posedge reset or posedge clk)
   begin : process_4
   if (reset == 1'b 1)
      begin
      align_done        <= 1'b 0;   
      enable_deskew_reg <= 1'b 1; 
      enable_deskew     <= 1'b 0;  
      end
   else
      begin
      
         `ifdef USE_CLK_ENA
            if(clk_ena == 1'b 1)
            begin
         `endif      
      
              if (next_state == STATE_TYP_LOSS_ALIGN)
                 begin
                 align_done <= 1'b 0;   
                 end
              else if (next_state == STATE_TYP_ALIGN_ACQ1 )
                 begin
                 align_done <= 1'b 1;   
                 end
              
              if (next_state == STATE_TYP_LOSS_ALIGN)
                 begin
                 enable_deskew_reg <= 1'b 1;   
                 end
              else if (next_state == STATE_TYP_ALIGN_DET1 )
                 begin
                 enable_deskew_reg <= 1'b 0;   
                 end
                 
              enable_deskew <= enable_deskew_reg ;
         
         `ifdef USE_CLK_ENA
            end
         `endif      
            
      end
   end

endmodule // module lane_dskew_stm